<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Exporting objects</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.76.1">
<link rel="home" href="index.html" title="GIO 参考手册">
<link rel="up" href="ch29.html" title="Migrating to GDBus">
<link rel="prev" href="ch29s05.html" title="Client-side GObject bindings">
<link rel="next" href="gio-hierarchy.html" title="Object Hierarchy">
<meta name="generator" content="GTK-Doc V1.17 (XML mode)">
<link rel="stylesheet" href="style.css" type="text/css">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table class="navigation" id="top" width="100%" summary="Navigation header" cellpadding="2" cellspacing="2"><tr valign="middle">
<td><a accesskey="p" href="ch29s05.html"><img src="left.png" width="24" height="24" border="0" alt="Prev"></a></td>
<td><a accesskey="u" href="ch29.html"><img src="up.png" width="24" height="24" border="0" alt="Up"></a></td>
<td><a accesskey="h" href="index.html"><img src="home.png" width="24" height="24" border="0" alt="Home"></a></td>
<th width="100%" align="center">GIO 参考手册</th>
<td><a accesskey="n" href="gio-hierarchy.html"><img src="right.png" width="24" height="24" border="0" alt="Next"></a></td>
</tr></table>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="id3148029"></a>Exporting objects</h2></div></div></div>
<p>
      With dbus-glib, exporting an object over D-Bus works by generating
      a bunch of glue code from your introspection XML with
      <span class="command"><strong>dbus-binding-tool</strong></span>. The glue code gets included in
      your source, and you need to call
      </p>
<div class="informalexample"><pre class="programlisting">
  dbus_g_object_type_install_info (TYPE_MYOBJECT,
                                   &amp;dbus_glib_myobject_object_info);
      </pre></div>
<p>
      in your <code class="function">class_init()</code> function to tell dbus-glib about your type.
      To actually export an instance, you call
      </p>
<div class="informalexample"><pre class="programlisting">
  dbus_g_connection_register_g_object (system_bus_connection,
                                       my_object_path,
                                       G_OBJECT (my_object));
      </pre></div>
<p>

    </p>
<p>
      The GDBus way of exporting an object works by embedding the
      introspection XML in the source, creating introspection data
      structures from it with <a class="link" href="gio-D-Bus-Introspection-Data.html#g-dbus-node-info-new-for-xml" title="g_dbus_node_info_new_for_xml ()"><code class="function">g_dbus_node_info_new_for_xml()</code></a>, and
      passing that along when you register the object:
      </p>
<div class="informalexample"><pre class="programlisting">

  static const gchar introspection_xml[] =
    "&lt;node&gt;"
    "  &lt;interface name='org.gtk.GDBus.TestPeerInterface'&gt;"
    "    &lt;method name='HelloWorld'&gt;"
    "      &lt;arg type='s' name='greeting' direction='in'/&gt;"
    "      &lt;arg type='s' name='response' direction='out'/&gt;"
    "    &lt;/method&gt;"
    "  &lt;/interface&gt;"
    "&lt;/node&gt;";

  /* parse introspection data */
  introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);

  /
  id = g_dbus_connection_register_object (connection,
                                          "/org/gtk/GDBus/TestObject",
                                          "org.gtk.GDBus.TestPeerInterface",
                                          introspection_data-&gt;interfaces[0],
                                          &amp;interface_vtable,
                                          NULL,  /* user_data */
                                          NULL,  /* user_data_free_func */
                                          NULL); /* GError** */


    </pre></div>
<p>
    </p>
<p>
      The actual implementation of the exported object is done by specifying
      a <a class="link" href="gio-GDBusConnection.html#GDBusInterfaceVTable" title="GDBusInterfaceVTable"><span class="type">GDBusInterfaceVTable</span></a> that has <code class="function">method_call()</code>, <code class="function">get_property()</code> and
      <code class="function">set_property()</code> methods. There is no direct support beyond that for
      exporting <a href="../gobject/gobject-The-Base-Object-Type.html#GObject"><span class="type">GObjects</span></a>, so there is quite a bit of manual work involved,
      as you can see in the following example.
    </p>
<p>
      Since the VTable methods don't have any direct <a href="../gobject/gobject-The-Base-Object-Type.html#GObject"><span class="type">GObject</span></a> support, we
      pass the exported object as <em class="parameter"><code>user_data</code></em>. Also note that we have to handle
      the emission of the PropertiesChanged signal ourselves, by connecting
      to ::notify.
    </p>
<div class="example">
<a name="gdbus-export"></a><p class="title"><b>Example 20. Exporting a GObject</b></p>
<div class="example-contents"><pre class="programlisting">#include &lt;gio/gio.h&gt;
#include &lt;stdlib.h&gt;

/* ---------------------------------------------------------------------------------------------------- */

/* The object we want to export */
typedef struct _MyObjectClass MyObjectClass;
typedef struct _MyObject MyObject;

struct _MyObjectClass
{
  GObjectClass parent_class;
};

struct _MyObject
{
  GObject parent_instance;

  gint count;
  gchar *name;
};

enum
{
  PROP_0,
  PROP_COUNT,
  PROP_NAME
};

G_DEFINE_TYPE (MyObject, my_object, G_TYPE_OBJECT);

static void
my_object_finalize (GObject *object)
{
  MyObject *myobj = (MyObject*)object;

  g_free (myobj-&gt;name);

  G_OBJECT_CLASS (my_object_parent_class)-&gt;finalize (object);
}

static void
my_object_init (MyObject *object)
{
  object-&gt;count = 0;
  object-&gt;name = NULL;
}

static void
my_object_get_property (GObject    *object,
                        guint       prop_id,
                        GValue     *value,
                        GParamSpec *pspec)
{
  MyObject *myobj = (MyObject*)object;

  switch (prop_id)
    {
    case PROP_COUNT:
      g_value_set_int (value, myobj-&gt;count);
      break;

    case PROP_NAME:
      g_value_set_string (value, myobj-&gt;name);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

static void
my_object_set_property (GObject      *object,
                        guint         prop_id,
                        const GValue *value,
                        GParamSpec   *pspec)
{
  MyObject *myobj = (MyObject*)object;

  switch (prop_id)
    {
    case PROP_COUNT:
      myobj-&gt;count = g_value_get_int (value);
      break;

    case PROP_NAME:
      g_free (myobj-&gt;name);
      myobj-&gt;name = g_value_dup_string (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

static void
my_object_class_init (MyObjectClass *class)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);

  gobject_class-&gt;finalize = my_object_finalize;
  gobject_class-&gt;set_property = my_object_set_property;
  gobject_class-&gt;get_property = my_object_get_property;

  g_object_class_install_property (gobject_class,
                                   PROP_COUNT,
                                   g_param_spec_int ("count",
                                                     "Count",
                                                     "Count",
                                                     0, 99999, 0,
                                                     G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_NAME,
                                   g_param_spec_string ("name",
                                                        "Name",
                                                        "Name",
                                                        NULL,
                                                        G_PARAM_READWRITE));
}

/* A method that we want to export */
void
my_object_change_count (MyObject *myobj,
                        gint      change)
{
  myobj-&gt;count = 2 * myobj-&gt;count + change;

  g_object_notify (G_OBJECT (myobj), "count");
}

/* ---------------------------------------------------------------------------------------------------- */

static GDBusNodeInfo *introspection_data = NULL;

/* Introspection data for the service we are exporting */
static const gchar introspection_xml[] =
  "&lt;node&gt;"
  "  &lt;interface name='org.myorg.MyObject'&gt;"
  "    &lt;method name='ChangeCount'&gt;"
  "      &lt;arg type='i' name='change' direction='in'/&gt;"
  "    &lt;/method&gt;"
  "    &lt;property type='i' name='Count' access='read'/&gt;"
  "    &lt;property type='s' name='Name' access='readwrite'/&gt;"
  "  &lt;/interface&gt;"
  "&lt;/node&gt;";


static void
handle_method_call (GDBusConnection       *connection,
                    const gchar           *sender,
                    const gchar           *object_path,
                    const gchar           *interface_name,
                    const gchar           *method_name,
                    GVariant              *parameters,
                    GDBusMethodInvocation *invocation,
                    gpointer               user_data)
{
  MyObject *myobj = user_data;

  if (g_strcmp0 (method_name, "ChangeCount") == 0)
    {
      gint change;
      g_variant_get (parameters, "(i)", &amp;change);

      my_object_change_count (myobj, change);

      g_dbus_method_invocation_return_value (invocation, NULL);
    }
}

static GVariant *
handle_get_property (GDBusConnection  *connection,
                     const gchar      *sender,
                     const gchar      *object_path,
                     const gchar      *interface_name,
                     const gchar      *property_name,
                     GError          **error,
                     gpointer          user_data)
{
  GVariant *ret;
  MyObject *myobj = user_data;

  ret = NULL;
  if (g_strcmp0 (property_name, "Count") == 0)
    {
      ret = g_variant_new_int32 (myobj-&gt;count);
    }
  else if (g_strcmp0 (property_name, "Name") == 0)
    {
      ret = g_variant_new_string (myobj-&gt;name ? myobj-&gt;name : "");
    }

  return ret;
}

static gboolean
handle_set_property (GDBusConnection  *connection,
                     const gchar      *sender,
                     const gchar      *object_path,
                     const gchar      *interface_name,
                     const gchar      *property_name,
                     GVariant         *value,
                     GError          **error,
                     gpointer          user_data)
{
  MyObject *myobj = user_data;

  if (g_strcmp0 (property_name, "Count") == 0)
    {
      g_object_set (myobj, "count", g_variant_get_int32 (value), NULL);
    }
  else if (g_strcmp0 (property_name, "Name") == 0)
    {
      g_object_set (myobj, "name", g_variant_get_string (value, NULL), NULL);
    }

  return TRUE;
}


/* for now */
static const GDBusInterfaceVTable interface_vtable =
{
  handle_method_call,
  handle_get_property,
  handle_set_property
};

static void
send_property_change (GObject         *obj,
                      GParamSpec      *pspec,
                      GDBusConnection *connection)
{
  GVariantBuilder *builder;
  GVariantBuilder *invalidated_builder;
  MyObject *myobj = (MyObject *)obj;

  builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
  invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));

  if (g_strcmp0 (pspec-&gt;name, "count") == 0)
    g_variant_builder_add (builder,
                           "{sv}",
                           "Count", g_variant_new_int32 (myobj-&gt;count));
  else if (g_strcmp0 (pspec-&gt;name, "name") == 0)
    g_variant_builder_add (builder,
                           "{sv}",
                           "Name", g_variant_new_string (myobj-&gt;name ? myobj-&gt;name : ""));

  g_dbus_connection_emit_signal (connection,
                                 NULL,
                                 "/org/myorg/MyObject",
                                 "org.freedesktop.DBus.Properties",
                                 "PropertiesChanged",
                                 g_variant_new ("(sa{sv}as)",
                                                "org.myorg.MyObject",
                                                builder,
                                                invalidated_builder),
                                 NULL);
}

static void
on_bus_acquired (GDBusConnection *connection,
                 const gchar     *name,
                 gpointer         user_data)
{
  MyObject *myobj = user_data;
  guint registration_id;

  g_signal_connect (myobj, "notify",
                    G_CALLBACK (send_property_change), connection);
  registration_id = g_dbus_connection_register_object (connection,
                                                       "/org/myorg/MyObject",
                                                       introspection_data-&gt;interfaces[0],
                                                       &amp;interface_vtable,
                                                       myobj,
                                                       NULL,  /* user_data_free_func */
                                                       NULL); /* GError** */
  g_assert (registration_id &gt; 0);
}

static void
on_name_acquired (GDBusConnection *connection,
                  const gchar     *name,
                  gpointer         user_data)
{
}

static void
on_name_lost (GDBusConnection *connection,
              const gchar     *name,
              gpointer         user_data)
{
  exit (1);
}

int
main (int argc, char *argv[])
{
  guint owner_id;
  GMainLoop *loop;
  MyObject *myobj;

  g_type_init ();

  /* We are lazy here - we don't want to manually provide
   * the introspection data structures - so we just build
   * them from XML.
   */
  introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
  g_assert (introspection_data != NULL);

  myobj = g_object_new (my_object_get_type (), NULL);

  owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
                             "org.myorg.MyObject",
                             G_BUS_NAME_OWNER_FLAGS_NONE,
                             on_bus_acquired,
                             on_name_acquired,
                             on_name_lost,
                             myobj,
                             NULL);

  loop = g_main_loop_new (NULL, FALSE);
  g_main_loop_run (loop);

  g_bus_unown_name (owner_id);

  g_dbus_node_info_unref (introspection_data);

  g_object_unref (myobj);

  return 0;
}
</pre></div>
</div>
<br class="example-break">
</div>
<div class="footer">
<hr>
          Generated by GTK-Doc V1.17</div>
</body>
</html>